#include "Cubemap.h"
#include <algorithm>
using namespace std;
#pragma warning (disable : 4244 )

Cubemap::Cubemap(){inited = false;};


void Cubemap::init(const char * fileup, const char * filedown, const char * fileback, const char * fileforward, const char * fileright, const char * fileleft)
{
	up=Image();
	down=Image();
	back=Image();
	forward=Image();
	left=Image();
	right=Image();
	if(!up.loadTGA(fileup))return;
	if(!down.loadTGA(filedown))return;
	if(!back.loadTGA(fileback))return;
	if(!forward.loadTGA(fileforward))return;
	if(!right.loadTGA(fileright))return;
	if(!left.loadTGA(fileleft))return;
	inited=true;
}




COLOR Cubemap::getCubeMapColor(const CLine &line)
{
  VECTOR rayDir = line.dir;
  COLOR color = COLOR(0,0,0);
  if(!inited)
  {
    return color;
  }
  if ((fabs(rayDir.x) >= fabs(rayDir.y)) && (fabs(rayDir.x) >= fabs(rayDir.z)))
  {
    if (rayDir.x > 0.0f)
    {
      //read right cube face
	  float u = 1.0f - ((float)rayDir.z / (float)rayDir.x+ 1.0f) * 0.5f;
	  float v = ((float)rayDir.y / (float)rayDir.x+ 1.0f) * 0.5f;
	  color = right.getPixelColorUV(u ,v);
    }
    else if (rayDir.x < 0.0f)
    {
		//read left cube face
		float u = 1.0f - ((float)rayDir.z / (float)rayDir.x+ 1.0f) * 0.5f;
		float v = 1.0f - ( (float)rayDir.y / (float)rayDir.x + 1.0f) * 0.5f;
		color = left.getPixelColorUV(u ,v);
    }
  }
  else if ((fabs(rayDir.y) >= fabs(rayDir.x)) && (fabs(rayDir.y) >= fabs(rayDir.z)))
  {
    if (rayDir.y > 0.0f)
    {
		//read up cube face
		float u = ((float)rayDir.x / (float)rayDir.y + 1.0f) * 0.5f;
		float v = 1.0f - ((float)rayDir.z/ (float)rayDir.y + 1.0f) * 0.5f;
		 color = up.getPixelColorUV(u ,v);
    }
    else if (rayDir.y < 0.0f)
    {
		//read down cube face
		float u =  1.0f - ((float)rayDir.x / (float)rayDir.y + 1.0f) * 0.5f;
		float v = ((float)rayDir.z/(float)rayDir.y + 1.0f) * 0.5f;
       color = down.getPixelColorUV(u ,v);
    }
  }
  else if ((fabs(rayDir.z) >= fabs(rayDir.x)) 
           && (fabs(rayDir.z) >= fabs(rayDir.y)))
  {
    if (rayDir.z > 0.0f)
    {
		//read forward cube face
		float u = ((float)rayDir.x / (float)rayDir.z + 1.0f) * 0.5f;
		float v = ((float)rayDir.y/(float)rayDir.z + 1.0f) * 0.5f;
       color = forward.getPixelColorUV(u ,v);
    }
    else if (rayDir.z < 0.0f)
    {
		//read back cube face
		float u = ((float)rayDir.x / (float)rayDir.z + 1.0f) * 0.5f;
		float v =  1.0f - ((float)rayDir.y /(float)rayDir.z+1) * 0.5f;
		 color = back.getPixelColorUV(u ,v);
    }
  }

  return color;
}

COLOR Image::getPixelColorUV(float u, float v)
{
	int sizeU = this->width;
	int sizeV = this->height;

	u = fabsf(u);
    v = fabsf(v);
    int umin = int(sizeU * u);
    int vmin = int(sizeV * v);
    int umax = int(sizeU * u) + 1;
    int vmax = int(sizeV * v) + 1;
    float ucoef = fabsf(sizeU * u - umin);
    float vcoef = fabsf(sizeV * v - vmin);
    
    umin = min(max(umin, 0), sizeU - 1);
    umax = min(max(umax, 0), sizeU - 1);
    vmin = min(max(vmin, 0), sizeV - 1);
    vmax = min(max(vmax, 0), sizeV - 1);

    //color pixels interpolation
	COLOR color1 = getPixelColor(vmin, umin);
	COLOR color2 = getPixelColor(vmin, umax);
	COLOR color3 = getPixelColor(vmax, umin);
	COLOR color4 = getPixelColor(vmax, umax);

    COLOR color = 
        (1.0f - vcoef) * 
        ((1.0f - ucoef) * getPixelColor(vmin, umin) + ucoef * getPixelColor(vmin, umax))
        +   vcoef * 
		((1.0f - ucoef) * getPixelColor(vmax, umin) + ucoef * getPixelColor(vmax, umax)) ;
	return color;


}


COLOR Image::getPixelColor(unsigned x, unsigned y)
{
	VECTOR color;
	if(x >= width || y>= height)
		return COLOR(0,0,0);
	 int r = data[x*3*width+y*3];
	 short int g = data[x*3*width+y*3+1];
	 unsigned b =  data[x*3*width+y*3+2];
	if(r<0)
		return color;
	color.x = r / 255.0f;	
	color.y = g/ 255.0f;
	color.z = b/ 255.0f;	
	return color;
}

bool Image::loadTGA(const char* filename)
{
    char TGAheader[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    char TGAcompare[12];
    char header[6];
    int  bytesPerPixel;
    int imageSize;
    int temp;
  

    FILE * file = fopen(filename, "rb");
    
    if (file == NULL || fread(TGAcompare, 1, sizeof(TGAcompare), file) != sizeof(TGAcompare) ||
        memcmp(TGAheader, TGAcompare, sizeof(TGAheader)) != 0 ||
        fread(header, 1, sizeof(header), file) != sizeof(header))
    {
        if (file == NULL)
            return false;
        else
        {
            fclose(file);
            return false;
        }
    }
    
    width = header[1] * 256 + header[0];
    height = header[3] * 256 + header[2];
    
    if (width <= 0 || height <= 0 || (header[4] != 24 && header[4] != 32))
    {
        fclose(file);
		return false;
    }
    
    bpp = header[4];
    bytesPerPixel = bpp / 8;
    imageSize = width * height * bytesPerPixel;
    
    data = (unsigned char*)malloc(imageSize);
    
    if (data == NULL || fread(data, 1, imageSize, file) != imageSize)
    {
        if (data != NULL)
            free(data);
            
        fclose(file);
        return false;
    }
    
    for (int i = 0; i < int(imageSize); i += bytesPerPixel)
    {
        temp = data[i];
        data[i] = data[i + 2];
        data[i + 2] = temp;
    }
    
    fclose(file);
	return true;
}

